﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Security;
using System.Web.Mvc;
using System.Web.Http.Controllers;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Seven.Member.Web.Model;
using Seven.Tools;
using Seven.Tools.Extension;
using Seven.Web.Http;

namespace Seven.Member.Web
{
    /// <summary>
    /// 用于验证登录身份信息是否有效。
    /// </summary>
    public class LoginModelUtility
    {
        private const string _AUTH_COOKIE_NAME = "SevenLoginCookieName";


        #region 获取和设置 ASP.NET MVC 请求中的登录用户身份信息

        /// <summary>
        /// 获取 ASP.NET MVC 过滤器拦截到请求中的用户登录身份验证信息。
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public static LoginModel GetLoginModel(HttpContextBase httpContext)
        {
            if (httpContext != null && httpContext.Request != null && httpContext.Request.Cookies != null)
            {
                HttpCookie cookie = httpContext.Request.Cookies[FormsAuthentication.FormsCookieName];
                try
                {
                    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
                    LoginModel model = JsonConvert.DeserializeObject<LoginModel>(ticket.UserData);
                    return model;
                }
                catch
                {
                    new Exception("无法从FormsAuthenticationTicket中获取当前登录信息，更新FormsAuthenticationTicket失败。");
                }
            }
            return null;
        }
        
        /// <summary>
        /// 设置 ASP.NET MVC 中的用户登录身份验证信息。
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="model"></param>
        public static void SetLoginModel(HttpContextBase httpContext, LoginModel model)
        {
            if (httpContext != null && httpContext.Response != null && model != null)
            {
                SetLoginModel(httpContext.Response, model);
            }
        }

        /// <summary>
        /// 设置 ASP.NET MVC 中的用户登录身份验证信息。
        /// </summary>
        /// <param name="response"></param>
        /// <param name="model"></param>
        public static void SetLoginModel(HttpResponseBase response, LoginModel model)
        {
            if (response == null || response.Cookies == null || model == null)
            { return; }

            string modelText = JsonConvert.SerializeObject(model);

            int timeout = Seven.Member.Common.Config.SessionTimeout;
            DateTime expiration = timeout == 0 ? DateTime.Now.AddYears(10) : DateTime.Now.AddMinutes(timeout);

            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, model.Account, DateTime.Now, expiration, false, modelText);
            string encrptyTicket = FormsAuthentication.Encrypt(ticket);

            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encrptyTicket);
            cookie.Expires = ticket.Expiration;

            response.Cookies.Add(cookie);
        }

        #endregion


        #region 获取 ASP.NET WebAPI 请求中的登录用户身份信息

        /// <summary>
        /// 获取 WebAPI 过滤器拦截到请求中的用户登录身份验证信息。
        /// </summary>
        /// <param name="actionContext"></param>
        /// <returns></returns>
        public static LoginModel GetLoginModel(HttpActionContext actionContext)
        {
            Check.NotNull(actionContext);

            HttpRequestMessage request = actionContext.Request;
            HttpContentHeaders headers = request.Content.Headers;
            string content = null;

            if (headers != null && headers.ContentType != null && headers.ContentType.MediaType != null
                && headers.ContentType.MediaType.IndexOf("form", StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                HttpContextBase context = request.GetHttpContext();
                if (context != null && context.Request != null && context.Request.Form != null)
                {
                    long position = context.Request.InputStream.Position;
                    content = context.Request.Form["data"];
                    if (context.Request.InputStream.CanSeek)
                    { context.Request.InputStream.Position = position; }
                }
                else if (HttpContext.Current != null && HttpContext.Current.Request != null && HttpContext.Current.Request.Form != null)
                {
                    long position = context.Request.InputStream.Position;
                    content = HttpContext.Current.Request.Form["data"];
                    if (context.Request.InputStream.CanSeek)
                    { context.Request.InputStream.Position = position; }
                }
            }

            if (string.IsNullOrWhiteSpace(content))
            { content = request.Content.ReadContentAsString(); }

            if (string.IsNullOrWhiteSpace(content))
            { return null; }

            string text = HttpUtility.UrlDecode(content.Trim());
            return GetHttpLoginModel(text);
        }


        private static LoginModel GetHttpLoginModel(string text)
        {
            string temp = text;
            if (string.IsNullOrWhiteSpace(temp))
            { return null; }

            if (temp.StartsWith("json=", StringComparison.InvariantCultureIgnoreCase))
            {
                temp = temp.Substring(5).Trim();
                return GetHttpLoginModel(temp);
            }
            if (temp.StartsWith("json:", StringComparison.InvariantCultureIgnoreCase))
            {
                temp = temp.Substring(5).Trim();
                return GetHttpLoginModel(temp);
            }
            if (temp.StartsWith("{") && temp.EndsWith("}"))
            {
                temp = temp.Substring(1, temp.Length - 2).Trim();
                return GetHttpLoginModel(temp);
            }

            string jsonText = "{" + temp + "}";
            return GetJsonStringLoginModel(jsonText);
        }

        private static LoginModel GetJsonStringLoginModel(string text)
        {
            LoginModel model = null;
            try
            {
                JObject json = JsonConvert.DeserializeObject(text) as JObject;
                if (json == null)
                { return model; }

                model = GetJsonObjectLoginModel(json);
            }
            catch
            {
                new Exception("无法从上下文中获取当前登录信息，更新FormsAuthenticationTicket失败。");
            }
            return model;
        }

        private static LoginModel GetJsonObjectLoginModel(JObject json)
        {
            if (json == null)
            { return null; }

            string token = GetTokenCodeFromJson(json);
            string account = GetUserCodeFromJson(json);
            string imei = GetIMEIFromJson(json);

            return new LoginModel() { Token = token, Account = account, IMEI = imei };
        }
        
        private static string GetTokenCodeFromJson(JObject json)
        {
            if (json == null)
            { return string.Empty; }

            string[] names = { "TOKEN", "Token", "token" };
            foreach (var name in names)
            {
                JToken jToken = null;
                if (json.TryGetValue(name, out jToken))
                { return jToken.Value<string>(); }
            }
            return string.Empty;
        }

        private static string GetUserCodeFromJson(JObject json)
        {
            if (json == null)
            { return string.Empty; }

            string[] names = { "ACCOUNT", "Account", "account" };
            foreach (var name in names)
            {
                JToken jToken = null;
                if (json.TryGetValue(name, out jToken))
                { return jToken.Value<string>(); }
            }
            return string.Empty;
        }

        private static string GetIMEIFromJson(JObject json)
        {
            if (json == null)
            { return string.Empty; }

            string[] names = { "IMEI", "Imei", "imei" };
            foreach (var name in names)
            {
                JToken jToken = null;
                if (json.TryGetValue(name, out jToken))
                { return jToken.Value<string>(); }
            }
            return string.Empty;
        }

        #endregion
        

        #region 验证登录身份

        /// <summary>
        /// 验证登录身份信息是否有效。
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static bool Validate(LoginModel model)
        {
            if (model == null || string.IsNullOrWhiteSpace(model.Account) || string.IsNullOrWhiteSpace(model.Token))
            { return false; }

            if (string.IsNullOrWhiteSpace(model.IMEI))
            {
                return ValidateUserLoginStatus(model.Account, model.Token);
            }
            else
            {
                return ValidateUserPhoneLoginStatus(model.Account, model.IMEI, model.Token);
            }
        }


        private static bool ValidateUserLoginStatus(string account, string tokenText)
        {
            Guid key = Guid.Empty;
            if (!Guid.TryParse(tokenText, out key))
            { return false; }

            return MemberClient.ValidateUserTokenLoginState(account, key);
        }

        private static bool ValidateUserPhoneLoginStatus(string account, string imei, string tokenText)
        {
            Guid key = Guid.Empty;
            if (!Guid.TryParse(tokenText, out key))
            { return false; }

            return MemberClient.ValidateUserPhoneTokenLoginState(account, imei, key);
        }

        #endregion
    }
}
